<template>
  <div>
    <a-upload-dragger
      style='width: 100%;min-height: 35vh;'
      name='file'
      :multiple='true'
      :file-list='fileList'
      :remove='handleRemove'
      :before-upload='beforeUpload'
    >
      <p class='ant-upload-drag-icon'>
        <a-icon type='inbox' />
      </p>
      <p class='ant-upload-text'>
        单击或拖动文件到此区域进行上传
      </p>
      <p class='ant-upload-hint'>
        支持单个或批量上传
      </p>
      
    </a-upload-dragger>
  </div>
</template>

<script>
import SparkMD5 from 'spark-md5'
import axios from 'axios'
import { mergeFile, uploadChunk, uploadSmallFile } from '@/api/uploadFile'

export default {
  props: {
    curPath: {
      required: true,
      type: String
    }
  },
  data() {
    return {
      chunks: [],
      fileList: [],
      fileMd5: '',
      fileName: '',
      CHUNK_SIZE: 1024 * 1024 * 10
    }
  },
  methods: {
    handleRemove(file) {
      const index = this.fileList.indexOf(file)
      const newFileList = this.fileList.slice()
      newFileList.splice(index, 1)
      this.fileList = newFileList
    },
    beforeUpload(file) {
      this.fileList = [...this.fileList, file]
      return false
    },
    async onFileUpload() {
      const { fileList } = this
      if (fileList.length === 0) {
        this.$message.error('请选择要上传的单个或多个文件')
        return
      }
      try {
        for (const selectedFile of fileList) {
          const fileSize = selectedFile.size
          if (fileSize <= this.CHUNK_SIZE) {
            // 小文件直接上传
            const formData = new FormData()
            formData.append('file', selectedFile)
            formData.append('curPath', this.curPath)
            uploadSmallFile(formData).then(() => {
              this.openNotificationWithIcon('success', '文件上传成功', '文件: ' + selectedFile.name)
            })
          } else {
            // 文件大于10M分片上传
            this.fileName = selectedFile.name
            this.chunks = this.createChunks(selectedFile, this.CHUNK_SIZE)
            this.fileMd5 = await this.getMD5(selectedFile)
            // 上传分片
            await this.uploadChunk(this.chunks)
            // 合并分片
            this.mergeFile()
          }
        }
        this.fileList = []
        this.$emit('onChangeModelStatus', false);
      } catch (error) {
        console.error('An error occurred:', error)
      }
    },
    createChunks(file, chunkSize) {
      const result = []
      for (let i = 0; i < file.size; i += chunkSize) {
        result.push(file.slice(i, i + chunkSize))
      }
      return result
    },
    async uploadChunk(chunks) {
      const data = chunks.map((chunk, index) => {
        return {
          chunk,
          fileMd5: this.fileMd5,
          chunkIndex: index
        }
      })
      const formDataList = data.map((item) => {
        const formData = new FormData()
        formData.append('file', item.chunk)
        formData.append('fileMd5', item.fileMd5)
        formData.append('chunk', item.chunkIndex)
        return formData
      })
      const maxRequest = 6 // 最大并发请求数
      let index = 0
      const taskPool = [] // 请求池
      while (index < formDataList.length) {
        const task = uploadChunk(formDataList[index]).then(() => {
          taskPool.splice(taskPool.findIndex(item => item === task))
        })
        taskPool.push(task)
        if (taskPool.length >= maxRequest) {
          await Promise.all(taskPool)
        }
        index++
      }
      await Promise.all(taskPool)
    },
    // 计算MD5
    getMD5(file) {
      return new Promise((resolve) => {
        const spark = new SparkMD5.ArrayBuffer()
        const fileReader = new FileReader()
        fileReader.onload = (e) => {
          spark.append(e.target.result)
          resolve(spark.end())
        }
        fileReader.readAsArrayBuffer(file)
      })
    },
    mergeFile() {
      let data = {
        fileMd5: this.fileMd5,
        fileName: this.fileName,
        chunkTotal: this.chunks.length,
        curPath: this.curPath
      }
      mergeFile(data).then(() => {
        this.openNotificationWithIcon('success', '文件上传成功', '文件: ' + this.fileName)
      })
    },
    openNotificationWithIcon(type = 'success', message, description) {
      this.$notification[type]({
        message,
        description
      })
    }
  }
}
</script>